package manager

import (
	"context"
	gojson "encoding/json"
	"fmt"
	"github.com/tianjigames/fairy/constants"
	"github.com/tianjigames/fairy/dao"
	"github.com/tianjigames/fairy/model"
	"github.com/tianjigames/fairy/pojo"
	protos2 "github.com/tianjigames/fairy/protos"
	"github.com/tianjigames/fairy/util"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/component"
	constants2 "github.com/topfreegames/pitaya/constants"
	"github.com/topfreegames/pitaya/logger"
	"github.com/topfreegames/pitaya/queue"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	LoginManager *loginManager
	loginOnce sync.Once
	waitDisconnectTime = 3000*time.Millisecond
)

type (
	loginManager struct {
		BaseManager
		loginPlayerMap map[string]*model.LoginPlayer
		onlinePlayerInGameSvr int //在游戏服务器上的人数
		deleteRoleKeppTime time.Duration
		nLastsTime int64 //上一次处理掉线的时间
		waitLoginLastTime int64 //等待登录，持续时间
		waitLoginTick int
		waitLoginQueue *queue.BaseQueue                  //等待登录队列
		waitLoginPlayerMap map[string]*model.LoginPlayer //等待进入游戏服务器玩家列表
		commonMsg *protos2.LCPushWaitLoginNumRet
		loginLogics map[string]loginLogic
	}

	loginLogic interface {
		DoLogin(context.Context,*model.LoginInfo) error
	}

	localLoginLogic struct {
		component.Base
	}
)


func NewLoginManger() *loginManager {
	loginOnce.Do(func() {
		LoginManager = &loginManager{
			loginPlayerMap:make(map[string]*model.LoginPlayer,0),
			deleteRoleKeppTime: pitaya.GetConfig().GetDuration(constants2.LoginServerDeleteRoleKeepTime),
			waitLoginTick: 1000,
			waitLoginQueue: queue.NewBaseQueue(reflect.TypeOf("")),
			commonMsg: &protos2.LCPushWaitLoginNumRet{},
			loginLogics:map[string]loginLogic{
				pitaya.GetConfig().GetString(constants2.LoginServerLocalLoginChannelId): &localLoginLogic{},
			},
		}
	})
	return LoginManager
}

func (p *loginManager) RegisterLoginLogic(channelId string,logic loginLogic)  {
	p.loginLogics[channelId] = logic
}

func (p *loginManager) GetLoginLogic(channelId string) loginLogic {
	return p.loginLogics[channelId]
}

func (p *localLoginLogic) DoLogin(ctx context.Context,loginInfo *model.LoginInfo) error {
	s := pitaya.GetSessionFromCtx(ctx)

	m := make(map[string]string,2)
	err := gojson.Unmarshal([]byte(loginInfo.ChannelJson),&m)
	if err != nil {
		logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err.Error())
		err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
			return err1
		}
		return err
	}

	username := m["username"]
	password := m["password"]

	reqCode,err1 := p.checkParams(username,password)
	if err1 != nil {
		logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
		err2 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err2 != nil {
			logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err2.Error())
			return err2
		}
		return err1
	}

	if reqCode != 0 {
		err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
			return err1
		}
		return nil
	}


	isNewRegister := false
	var localAccountData *pojo.AccountData
	localAccountData,err = PlayerManager.GetAccountDataByUsernameAndChannelIdAndAppId(username,
		loginInfo.ChannelId,loginInfo.AppId)
	if err != nil {
		logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err.Error())
		err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
			return err1
		}
		return err
	}

	if loginInfo.LoginType == int32(protos2.LoginType_REGISTER) { //注册
		if localAccountData != nil {
			logger.Log.Infof("LocalAccountData is already registered,username=%s",username)
			err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.RegisterReUserError})
			if err1 != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
				return err1
			}
			return nil
		}

		isNewRegister = true
		localAccountData,err = PlayerManager.CreateLocalAccount(username,loginInfo.ChannelId,password,
			loginInfo.Mid,loginInfo.DeviceModel,loginInfo.AppId)
		if err != nil {
			logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err.Error())
			err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
			if err1 != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
				return err1
			}
			return err
		}

		if localAccountData == nil {
			logger.Log.Infof("LocalAccountData registered error!username=%s",username)
			err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
			if err1 != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
				return err1
			}
			return nil
		}
	}else{//登录
		if localAccountData == nil {
			var accountDatas []*pojo.AccountData
			accountDatas,err = PlayerManager.GetAccountDataByUsernameAndChannelId(username,loginInfo.ChannelId)
			if err != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err.Error())
				err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
				if err1 != nil {
					logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
					return err1
				}
				return err
			}

			if accountDatas == nil || len(accountDatas) == 0{
				logger.Log.Infof("LocalAccountData 查无此人,username=%s",username)
				err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginUsernameError})
				if err1 != nil {
					logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
					return err1
				}
				return nil
			}

			localAccountData,err = PlayerManager.CreateLocalAccount(username,loginInfo.ChannelId,password,
				loginInfo.Mid,loginInfo.DeviceModel,loginInfo.AppId)
			if err != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err.Error())
				err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
				if err1 != nil {
					logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
					return err1
				}
				return err
			}

			if localAccountData == nil {
				logger.Log.Infof("LocalAccountData registered error!username=%s",username)

				err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginUsernameError})
				if err1 != nil {
					logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
					return err1
				}
				return nil
			}
			isNewRegister = true
		}

		if password != localAccountData.Password{
			logger.Log.Infof("[CCLogin]wrong password,username=%s",username)
			err1 = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginPasswordError})
			if err1 != nil {
				logger.Log.Errorf("[LocalLoginLogic] DoLogin failed,err:%s",err1.Error())
				return err1
			}
			return nil
		}
	}

	//开始执行登录
	return LoginManager.DoLoginResult(ctx,true,loginInfo,localAccountData,isNewRegister,false)
}

func (p *localLoginLogic) checkParams(params ...string) (int32,error) {
	if params == nil || len(params) < 2 {
		return constants.LoginParamsError,nil
	}

	username := strings.Trim(params[0]," ")
	password := strings.Trim(params[1]," ")
	if len(username) == 0 || len(password) == 0 {
		return constants.LoginParamsError,nil
	}

	//检查用户名是否满足正则
	if !util.StringFilter.CheckAccount(username) {
		return constants.ContentInvalid,nil
	}

	if length := len(username);length < 6 || length > 20 {
		return constants.AccountLengthError,nil
	}
	return 0,nil
}


func (p *loginManager) DoLoginResult(ctx context.Context,isLoginSuccess bool,loginInfo *model.LoginInfo,
	accountData *pojo.AccountData,isNewRegister,isSwitchRole bool) error {
	s := pitaya.GetSessionFromCtx(ctx)
	if !isLoginSuccess {
		err := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err != nil {
			logger.Log.Errorf("[LoginManager] DoLoginResult failed,err:%s",err.Error())
			return err
		}
		return nil
	}

	retCode,err := p.checkAndCreateLoginPlayer(accountData,loginInfo)
	if err != nil {
		logger.Log.Errorf("DoLoginResult failed,error:%s",err.Error())
		err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LoginManager] DoLoginResult failed,err:%s",err1.Error())
			return err1
		}
		return err
	}

	if retCode != 0 {
		err = s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: retCode})
		if err != nil {
			logger.Log.Errorf("[LoginManager] DoLoginResult failed,err:%s",err.Error())
			return err
		}
		return nil
	}

	if !isNewRegister{
		err = p.dealUniqueLogin(ctx,accountData,isSwitchRole)
	}else{
		err =  p.succLoginRetResponse1(ctx,accountData,0,isNewRegister)
	}

	if err != nil {
		logger.Log.Errorf("[LoginManager] DoLoginResult failed,error:%s",err.Error())
		return err
	}

	return nil
}

func (p *loginManager) dealUniqueLogin(ctx context.Context,accountData *pojo.AccountData,isSwitchRole bool) error {
	s := pitaya.GetSessionFromCtx(ctx)

	loginPlayer := p.GetLoginPlayer(s.UID())
	if loginPlayer == nil {
		logger.Log.Errorf("[LoginManager] loginPlayer not exist,accountId=%d",accountData.AccountId)
		err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LoginManager] dealUniqueLogin failed,err:%s",err1.Error())
			return err1
		}
		return nil
	}

	err := p.bindAccountId(ctx,accountData.AccountId)
	if err != nil {
		logger.Log.Errorf("[LoginManager] dealUniqueLogin failed,err:%s",err.Error())
		err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LoginManager] dealUniqueLogin failed,err:%s",err1.Error())
			return err1
		}
		return err
	}

	err = p.succLoginRetResponse(ctx,accountData,false)
	if err != nil {
		logger.Log.Errorf("[LoginManager] dealUniqueLogin failed,err:%s",err.Error())
		return err
	}
	return nil
}

func (p *loginManager) bindAccountId(ctx context.Context,accountId int64) error {
	s := pitaya.GetSessionFromCtx(ctx)


	//账户绑定了|新的session 通知玩家管理服务器 踢出老的session下线
	sessionId := s.UID()
	err := pitaya.RPC(ctx, constants.LPAccountBindSessionRoute,&protos2.PLAccountBindSessionRet{},&protos2.LPAccountBindSession{
		AccountId: accountId,
		SessionId: sessionId,
	})

	if err != nil {
		logger.Log.Errorf("[LoginManager] bindAccountId failed,error:%s",err.Error())
		return err
	}

	err = s.Set(constants.UIdKey,strconv.FormatInt(accountId,10))
	if err != nil {
		logger.Log.Errorf("bindAccountId failed,error:%s",err.Error())
		return err
	}

	return nil
}

func (p *loginManager) succLoginRetResponse1(ctx context.Context,accountData *pojo.AccountData,
	nRetCode int32,isNewRegister bool) error {
	if (nRetCode == int32(0)){
		err := p.succLoginRetResponse(ctx,accountData,isNewRegister)
		if err != nil {
			logger.Log.Errorf("succLoginRetResponse1 failed,error:%s",err.Error())
			return err
		}

		err = p.bindAccountId(ctx,accountData.AccountId)
		if err != nil {
			logger.Log.Errorf("succLoginRetResponse1 failed,error:%s",err.Error())
			return err
		}

		return nil
	}else{
		s := pitaya.GetSessionFromCtx(ctx)
		loginPlayer := p.GetLoginPlayer(s.UID())

		loginPlayer.M_nLoginPlayerState = model.PlayerLoginWaitDisconnect
		loginPlayer.M_WaitRemTime = waitDisconnectTime.Milliseconds()


		err := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: nRetCode})
		if err != nil {
			logger.Log.Errorf("succLoginRetResponse1 failed,error:%s",err.Error())
			return err
		}

		return nil
	}
}

func (p *loginManager) succLoginRetResponse(ctx context.Context,accountData *pojo.AccountData,
	isNewRegister bool) error {
	s := pitaya.GetSessionFromCtx(ctx)

	var bNewRegist = int32(0)
	if isNewRegister {
		bNewRegist = 1
	}
	resp := &protos2.LCLoginRet{
		AccountId:accountData.AccountId,
		BNewRegist:bNewRegist,
		UpdateURL:accountData.Username,
		RoleInfo:make([]*protos2.LCRoleInfoRet,0),
	}

	loginPlayer := p.GetLoginPlayer(s.UID())

	roleList,err := PlayerManager.ListPlayerData(accountData,true)
	if err != nil {
		logger.Log.Errorf("[LoginManager] succLoginRetResponse failed,accountId=%d,error=%s",accountData.AccountId,err.Error())
		err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
		if err1 != nil {
			logger.Log.Errorf("[LoginManager] failed,err:%s",err1.Error())
			return err1
		}
		return err
	}

	size := 0
	if roleList != nil {
		size = len(roleList)
	}

	logger.Log.Infof("succLoginRetResponse accountId=%d,worldId=%d,roleList=%d",accountData.AccountId,
		accountData.WorldId,size)

	var r pojo.PlayerDataSlice = roleList
	if size > 3 {
		roleList = p.DealWithOverPlayer(accountData,&r)
	}else if accountData.WorldId == 0 && size == 0 {
		roleList,err = PlayerManager.ListPlayerData(accountData,false)
		if err != nil {
			logger.Log.Errorf("[LoginManager] succLoginRetResponse failed,accountId=%d,error=%s",accountData.AccountId,err.Error())
			err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
			if err1 != nil {
				logger.Log.Errorf("[LoginManager] failed,err:%s",err1.Error())
				return err1
			}
			return err
		}

		if roleList != nil && len(roleList) > 3 {
			r = roleList
			roleList = p.DealWithOverPlayer(accountData,&r)
		}
	}

	size = 0
	if roleList  != nil {
		size = len(roleList)
	}

	roleIndex := 0
	for i := 0; i < size;i++ {
		//遍历更新accountId
		update := false
		roleIndex ++
		playerData := roleList[i]
		if playerData.AccountId != accountData.AccountId {
			if playerData.ChannelId == accountData.ChannelId &&
				playerData.AccountName == accountData.Username && playerData.AppId == accountData.AppId {
				logger.Log.Infof("succLoginRetResponse reset playerData accountId,before=%d,after=%d,detail" +
					":channelId=%s,username=%s,appId=%s",playerData.AccountId,accountData.AccountId,
					accountData.ChannelId,accountData.Username,accountData.AppId)
				playerData.AccountId = accountData.AccountId
				update = true
			}else{
				logger.Log.Infof("succLoginRetResponse wrong guid in accountData:accountId=%d," +
					"allGuids=%s,wrong guid=%d",accountData.AccountId,accountData.AllPlayerGuids,playerData.Guid)
			}
		}


		//删除被锁的角色
		if playerData.RoleIndex != roleIndex {
			playerData.RoleIndex = roleIndex
			update = true
		}

		if update {
			err = dao.PlayerDataDao.Update(playerData,"playerid=?",playerData.PlayerId)
			if err != nil {
				logger.Log.Errorf("[LoginManager] succLoginRetResponse failed,accountId=%d,error=%s",accountData.AccountId,err.Error())
				err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
				if err1 != nil {
					logger.Log.Errorf("[LoginManager] failed,err:%s",err1.Error())
					return err1
				}
				return err
			}
		}

		if playerData.Status == pojo.RoleStateLock && util.Now() - playerData.DeleteRoleTime >= p.deleteRoleKeppTime.Milliseconds() {
			playerData.Status = pojo.RoleStateDelete
			playerData.DeleteRoleTime = 0
			err =  PlayerManager.DeletePlayer(accountData,playerData)
			if err != nil {
				logger.Log.Errorf("[LoginManger] succLoginRetResponse failed,accountId=%d,error=%s",accountData.AccountId,err.Error())
				err1 := s.Push(constants.LoginRetRoute,&protos2.LCLoginRet{RetCode: constants.LoginSystemUnknowError})
				if err1 != nil {
					logger.Log.Errorf("[LoginManager] failed,err:%s",err1.Error())
					return err1
				}
				return err
			}

			roleList = append(roleList[:i],roleList[i+1:]...)
			continue
		}

		resp.RoleInfo = append(resp.RoleInfo,playerData.NewLcRoleInfoRet())
	}

	loginPlayer.RoleInfo = roleList
	resp.RetCode = constants.SuccessRet
	err = s.Push(constants.LoginRetRoute,resp)
	if err != nil {
		logger.Log.Errorf("[LoginManager] failed,err:%s",err.Error())
		return err
	}

	return nil
}

func (p *loginManager) DealWithOverPlayer(accountData *pojo.AccountData,roleList *pojo.PlayerDataSlice) ([]*pojo.PlayerData) {
	sort.Sort(roleList)
	result := make([]*pojo.PlayerData,0)
	for i:=0; i<len(*roleList) && i < 3; i++{
		result = append(result,(*roleList)[i])
	}

	return result
}

/**
将玩家的信息注册到redis
 */
func (p *loginManager) checkAndCreateLoginPlayer(accountData *pojo.AccountData,
	loginInfo *model.LoginInfo) (int32,error)  {
	loginPlayer := p.GetOrCreateLoginPlayer(accountData,loginInfo)

	if loginPlayer != nil {
		if loginPlayer.M_nLoginPlayerState == model.PlayLoginStateForbid {
			return constants.LoginUserStateForbid,nil
		}

		if loginPlayer.M_nLoginPlayerState == model.PlayerLoginStateNeedActive {
			return constants.LoginUserNotActive,nil
		}

		return 0,nil
	}

	return 0,nil
}

func (p *loginManager) GetLoginPlayer(sessionId string) *model.LoginPlayer {
	return p.loginPlayerMap[sessionId]
}

/**
创建或者添加用户到redis
 */
func (p *loginManager) GetOrCreateLoginPlayer(accountData *pojo.AccountData,loginInfo *model.LoginInfo) *model.LoginPlayer {
	loginPlayer,ok := p.loginPlayerMap[loginInfo.SessionId]
	if !ok {
		loginPlayer = model.NewLoginPlayer(loginInfo)
		loginPlayer.AccountData = accountData
		loginPlayer.M_version = p.GetVersion()
	}

	if accountData.ForbidLoginTime >= util.Now(){
		loginPlayer.M_nLoginPlayerState = model.PlayLoginStateForbid
	}

	if p.isAccountActivity(accountData){
		loginPlayer.M_nLoginPlayerState = model.PlayerLoginNormal
	}else{
		loginPlayer.M_nLoginPlayerState = model.PlayerLoginStateNeedActive
	}
	p.loginPlayerMap[loginInfo.SessionId] = loginPlayer
	return loginPlayer
}

func (p *loginManager) isAccountActivity(accountData *pojo.AccountData) bool {
	openActiveCode := pitaya.GetConfig().GetBool("pitaya.game.loginserver.activecode_open")
	if openActiveCode && len(accountData.ActiveCode) == 0 {
		return false
	}
	return true
}

func (p *loginManager) GetVersion() string {
	return ""
}

func (p *loginManager) CheckPlayerNameResoult(roleName string,ctx context.Context,existName bool) (bool,error) {
	s := pitaya.GetSessionFromCtx(ctx)

	if existName {
		err := s.Push(constants.RoleCreateRetRoute,&protos2.LCCreateRoleRet{RetCode: constants.RoleReNameError})
		if err != nil {
			logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
			return false,err
		}
		return false,nil
	}

	loginPlayer := LoginManager.GetLoginPlayer(s.UID())
	if loginPlayer == nil {
		err := s.Push(constants.RoleCreateRetRoute,&protos2.LCCreateRoleRet{RetCode: constants.RoleNotRoundError})
		if err != nil {
			logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
			return false,err
		}
		return false,nil
	}

	accountData := loginPlayer.AccountData
	if accountData == nil {
		err := s.Push(constants.RoleCreateRetRoute,&protos2.LCCreateRoleRet{RetCode: constants.RoleNotRoundError})
		if err != nil {
			logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
			return false,err
		}
		return false,nil
	}

	nRoleIndex := loginPlayer.GetNewRoleIndex()
	if nRoleIndex <= 0 {
		err := s.Push(constants.RoleCreateRetRoute,&protos2.LCCreateRoleRet{RetCode: constants.RoleCreateFailIndex})
		if err != nil {
			logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
			return false,err
		}
		return false,nil
	}

	worldId := accountData.WorldId
	if worldId == 0{
		worldId = pitaya.GetConfig().GetInt(constants2.LoginServerWorldId)
	}

	globalData,err := p.GetWorldServer(accountData)
	if err != nil {
		logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
		return false,err
	}

	name := roleName
	if globalData != nil {
		name = fmt.Sprintf("%s%s",globalData.Worth,name)
	}

	roleData := &pojo.PlayerData{
		RoleIndex:  nRoleIndex,
		CareerId:   loginPlayer.M_CreateCareerId,
		SexId:      int8(loginPlayer.M_CreateSexId),
		Rolelevel:  pojo.RoleStartLevel,
		SceneId:    pojo.RoleStartSceneId,
		Direction:  pojo.RoleStartDirection,
		CreateTime: time.Now(),
		PosX:       0,
		PosY:       0,
		PosZ:       0,
		Hp:         -1,
		Mp:         -1,
		LastIp:     s.Get(constants2.RemoteAddrKey).(string),
	}

	err = PlayerManager.CreatePlayer(accountData,roleData)
	if err != nil {
		logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
		return false,err
	}

	if roleData == nil || roleData.PlayerId < 0 {
		logger.Log.Error("CheckPlayerNameResult failed,role data is nil")
		return false,nil
	}

	loginPlayer.AddRoleInfo(roleData)
	logger.Log.Infof("[CreateRole] create success!role guid=%d,roleName=%s",roleData.Guid,roleData.RoleName)
	addNewPlayer := &protos2.LWAddNewPlayer{
		PlayerGuId:roleData.Guid,
		Name:roleData.RoleName,
		AccountId:roleData.AccountId,
		Sexid:int32(roleData.SexId),
		AppId:roleData.AppId,
	}

	reply := &protos2.RpcResponse{}
	err = pitaya.RPC(ctx, constants.LWAddNewPlayerRoute,reply,addNewPlayer)
	if err != nil {
		logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
		return false,err
	}

	if reply.RetCode != 0 {
		return false,nil
	}

	playrId := int32(roleData.PlayerId)
	roleLevel := int32(roleData.Rolelevel)
	bankMoney := int32(roleData.BankMoney)
	gangName := ""
	vipLevel := int32(0)
	code := int32(0)
	resp := &protos2.LCCreateRoleRet{
		PlayerId:playrId,
		RoleGuid:roleData.Guid,
		RoleName:roleData.RoleName,
		RoleLevel:roleLevel,
		BankMoney:bankMoney,
		GangName:gangName,
		VipLevel:vipLevel,
		RetCode:code,
	}

	err = s.Push(constants.RoleCreateRetRoute,resp)
	if err != nil {
		logger.Log.Errorf("CheckPlayerNameResult failed,error：%s",err.Error())
		return false,err
	}

	return true,nil
}

func (p *loginManager) GetWorldServer(accountData *pojo.AccountData) (*pojo.GlobalData,error) {
	globalDatas := make([]*pojo.GlobalData,0)
	err := dao.GlobalDataDao.GetListByDb(&pojo.GlobalData{
		NKey: pojo.GlobalDataWorldIdKey,
	},&globalDatas)
	if err != nil {
		logger.Log.Errorf("GetWorldServer failed,error:%s",err.Error())
		return nil,err
	}

	if globalDatas == nil || len(globalDatas) == 0{
		return nil,nil
	}

	compareId := accountData.WorldId
	if compareId <= 0 {
		compareId = pitaya.GetConfig().GetInt(constants2.LoginServerWorldId)
	}
	for _,gloabalData := range globalDatas {
		if gloabalData.Id == compareId {
			return gloabalData,nil
		}
	}
	return nil,nil
}

/**
从等待登录游戏服的队列中取出一个玩家登录游戏服
 */
func (p *loginManager) WaitQueuePoll() error {
	e := p.waitLoginQueue.Poll()
	if e == nil {
		return nil
	}

	sessionId := e.Value.(string)
	loginPlayer,ok := p.waitLoginPlayerMap[sessionId]
	if !ok {
		return nil
	}

	delete(p.waitLoginPlayerMap,sessionId)
	p.commonMsg.Num = int32(0)
	logger.Log.Infof("checkServerOnlineNum who:%d waitLoginQueue:%d",loginPlayer.GetAccountId(),
		p.waitLoginQueue.Size())

	_,err := pitaya.SendPushToUsers(constants.LCPushWaitLoginNumRetRoute,p.commonMsg,[]string{sessionId},constants.SvTypeHall)
	if err != nil {
		logger.Log.Errorf("[LoginManager] WaitQueuePoll fail,error:%s",err.Error())
		return err
	}

	err = p.getGSInfo(sessionId,loginPlayer)
	if err != nil {
		logger.Log.Errorf("[LoginManager] WaitQueuePoll fail,error:%s",err.Error())
		return err
	}

	return nil
}

func (p *loginManager) CheckServerOnlineNum(ctx context.Context,req *protos2.WLCheckLoginNumRet) error {
	if req == nil {
		return nil
	}

	s := pitaya.GetSessionFromCtx(ctx)
	accountId := s.Int64(constants.UIdKey)
	loginPlayer := p.GetLoginPlayer(s.UID())
	if loginPlayer == nil || loginPlayer.M_nLoginPlayerState != model.PlayerLoginNormal {
		logger.Log.Errorf("CheckServerOnlineNum user account not login!accountId=%d",accountId)
		return nil
	}


	logger.Log.Infof("checkServerOnlineNum : wait:%d doLog:%d inLog:%d leaveNum:%d",
		p.waitLoginQueue.Size(),pitaya.ThreadPool.GetThread(constants.LoginThread).(*LoginThread).GetDoLoginPlayerNum(),len(p.loginPlayerMap),req.Num)
	//设置登录角色id
	loginPlayer.M_LoginPlayerId = int(req.PlayerId)
	reminNum := len(p.loginPlayerMap) - int(req.Num)
	if reminNum >= 0 {//有一部人需要排队,新来的人排队
		p.waitLoginQueue.Offer(s.UID())
		p.waitLoginPlayerMap[s.UID()] = loginPlayer
		num := int32(p.waitLoginQueue.Size())
		p.commonMsg.Num = num
		err := s.Push(constants.LCPushWaitLoginNumRetRoute,p.commonMsg)
		if err != nil {
			logger.Log.Errorf("[LoginManager] CheckServerOnlineNum failed,error:%s",err.Error())
			return err
		}
	}else {
		loginPlayer.M_nLoginPlayerState = model.PlayerLoginBeginGame
		err := p.getGSInfo(s.UID(),loginPlayer)
		if err != nil {
			logger.Log.Errorf("CheckServerOnlineNum failed,error=%s",err.Error())
			return err
		}

	}

	return nil
}

func (p *loginManager) getGSInfo(sessionId string,loginPlayer *model.LoginPlayer) error {
	accountData := loginPlayer.AccountData
	if accountData == nil {
		logger.Log.Errorf("getGSInfo failed,account = nil ")
		return nil
	}

	roleInfo := loginPlayer.GetRoleInfo(loginPlayer.M_LoginPlayerId)
	if roleInfo == nil || roleInfo.Status == pojo.RoleStateLock {
		return nil
	}

	reply := &protos2.WLGetGSInfoRet{}
	err := pitaya.RPC(context.Background(), constants.LWGetGSInfoRoute,reply,&protos2.LWGetGSInfo{
		PlayerData: roleInfo.GenerateMsgPlayerData(),
	})

	if err != nil {
		logger.Log.Errorf("getGSInfo failed,error:%s",err.Error())
		return err
	}

	beginGameRet := &protos2.LCBeginGameRet{}
	srvId := int32(-1)
	if loginPlayer == nil || loginPlayer.M_nLoginPlayerState != model.PlayerLoginBeginGame {
		beginGameRet.GameServerId = srvId
	}else {
		loginPlayer.M_nLoginPlayerState = model.PlayerLoginNormal
		if reply.GetServerInfo() != nil {
			beginGameRet.GameServerId = reply.ServerInfo.Id
			beginGameRet.GameServerIp = reply.ServerInfo.Ip
			beginGameRet.Ticket = reply.Ticket
		}else{
			beginGameRet.GameServerId = srvId
		}
	}

	_,err = pitaya.SendPushToUsers(constants.BeginGameRetRoute,beginGameRet,[]string{sessionId},constants.SvTypeConnector)
	if err != nil {
		logger.Log.Errorf("getGSInfo failed,error:%s",err.Error())
		return err
	}
	return nil
}

/**
处理掉线的玩家
 */
func (p *loginManager) Tick(nNow int64) error {
	if p.nLastsTime <= 0 {
		p.nLastsTime = nNow
	}

	if p.waitLoginLastTime <= 0 {
		p.waitLoginLastTime = nNow
	}

	//延时时间
	nDelayTime := nNow - p.nLastsTime
	removeList := make([]string,0)
	for sessionId,player := range p.loginPlayerMap {
		if player == nil {
			removeList = append(removeList,sessionId)
			continue
		}

		if player.M_nLoginPlayerState != model.PlayerLoginWaitDisconnect {
			continue
		}

		player.M_WaitRemTime = player.M_WaitRemTime - nDelayTime
		if player.M_WaitRemTime <= 0 {
			removeList = append(removeList,sessionId)
		}
	}

	for _,sessionId := range removeList {
		delete(p.loginPlayerMap,sessionId)
	}

	if len(removeList) > 0 {
		_,err := pitaya.SendKickToUsers(removeList, constants.SvTypeConnector) //服务器主动断开连接 通知world session关闭
		if err != nil {
			logger.Log.Errorf("[LoginManager] Tick failed,error=%s",err.Error())
		}

		//通知world服务器 玩家退出登录服

	}


	if nNow < p.waitLoginLastTime {
		return nil
	}

	p.waitLoginLastTime = nNow + int64(p.waitLoginTick)
	err := p.PushWaitLoginMsg()
	if err != nil {
		logger.Log.Errorf("[LoginManager] Tick failed,error=%s",err.Error())
		return err
	}

	return nil
}

/**
玩家断开连接时候，移除登录玩家
 */
func (p *loginManager) removeLoginPlayer(sessionId string) {
	if _,ok := p.loginPlayerMap[sessionId];ok {
		delete(p.loginPlayerMap,sessionId)
	}

	if _,ok := p.waitLoginPlayerMap[sessionId];ok{
		delete(p.waitLoginPlayerMap,sessionId)
	}
}

/**
给客户端推送当前有多少人等待连接
*/
func (p *loginManager) PushWaitLoginMsg() (err error) {
	if p.waitLoginQueue.Size() == 0 {
		return nil
	}

	rank := int32(1)
	for e := p.waitLoginQueue.List.Front();e != nil;e = e.Next() {
		p.commonMsg.Num = rank
		rank ++
		_,err = pitaya.SendPushToUsers(constants.LCPushWaitLoginNumRetRoute,p.commonMsg,[]string{e.Value.(string)}, constants.SvTypeConnector)
		if err != nil {
			logger.Log.Errorf("[LoginManager] PushWaitLoginMsg failed,error=%s",err.Error())
			return
		}
	}

	return nil
}

/**
获取在线玩家的数量：已经登录到登录服的玩家 + 登录到游戏服的玩家
 */
func (p *loginManager) getOnlinePlayerNum() int {
	return len(p.loginPlayerMap) + p.onlinePlayerInGameSvr
}

/**
开始登录
 */
func (p *loginManager) StartDoLogin(info *model.LoginInfo) error {
	err := pitaya.ThreadPool.GetThread(constants.LoginThread).(*LoginThread).AddNewLoginMessage(info)
	if err != nil {
		logger.Log.Errorf("[LoginManager] startDoLogin failed,error=%s",err.Error())
		return err
	}

	return nil
}
